import {
  findRecursiveChild,
  RuntimeError,
  RuntimeModelError,
} from '@ibiz-template/core';
import {
  ControlController,
  AppFuncCommand,
  IAppMenuController,
  IAppMenuEvent,
  Application,
  IAppMenuState,
  AppCounter,
} from '@ibiz-template/runtime';
import { IAppMenu, IAppMenuItem } from '@ibiz/model-core';

/**
 * 应用菜单控制器
 *
 * @author chitanda
 * @date 2022-07-24 15:07:07
 * @export
 * @class AppMenuController
 * @extends {ControlController}
 */
export class AppMenuController
  extends ControlController<IAppMenu, IAppMenuState, IAppMenuEvent>
  implements IAppMenuController
{
  app!: Application;

  protected initState(): void {
    super.initState();
    this.state.menuItemsState = {};
  }

  /**
   * 视图层级
   *
   * @readonly
   * @type {(number | undefined)}
   * @memberof AppMenuController
   */
  get routeDepth(): number | undefined {
    return this.view.modal.routeDepth;
  }

  protected async onCreated(): Promise<void> {
    await super.onCreated();

    this.app = await ibiz.hub.getApp(this.context.srfappid);

    // 初始化菜单项状态
    this.model.appMenuItems?.forEach(item => {
      this.initMenuItemState(item);
    });
  }

  /**
   * 菜单项点击回调，触发对应的应用功能
   *
   * @author chitanda
   * @date 2022-12-22 14:12:53
   * @param {string} id
   * @return {*}  {Promise<void>}
   */
  async onClickMenuItem(id: string, event?: MouseEvent): Promise<void> {
    const menuItem = findRecursiveChild(this.model, id, {
      compareField: 'id',
      childrenFields: ['appMenuItems'],
    }) as IAppMenuItem;
    if (!menuItem) {
      throw new RuntimeError(`找不到名为${id}的菜单项`);
    }

    this.evt.emit('onClick', {
      eventArg: id,
      event,
    });

    if (!menuItem.appFuncId) {
      throw new RuntimeModelError(menuItem, '没有配置应用功能');
    }

    const tempContext = this.context.clone();

    if (this.routeDepth) {
      Object.assign(tempContext, {
        toRouteDepth: this.routeDepth + 1,
      });
    }

    await ibiz.commands.execute(
      AppFuncCommand.TAG,
      menuItem.appFuncId,
      tempContext,
      this.params,
    );
  }

  /**
   * 初始化菜单项状态
   *
   * @author lxm
   * @date 2022-10-12 20:10:37
   * @param {AppMenuItemModel} menu
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  initMenuItemState(menu: IAppMenuItem): {
    visible: boolean;
    permitted: boolean;
  } {
    const result = { permitted: true, visible: true };
    if (menu.hidden) {
      result.visible = false;
    } else {
      let permitted = true;
      if (menu.accessKey) {
        permitted = this.app.authority.calcByResCode(menu.accessKey);
      }
      let visible = permitted;
      // 有子的计算子状态，如果本身显示但是子都不显示则不显示
      if (menu.appMenuItems?.length) {
        const childrenState = menu.appMenuItems.map(child => {
          return this.initMenuItemState(child).visible;
        });
        visible = visible && childrenState.includes(true);
      }
      result.permitted = permitted;
      result.visible = visible;
    }
    this.state.menuItemsState[menu.id!] = result;
    return result;
  }

  /**
   * 所有项平铺
   * @return {*}
   * @author: zhujiamin
   * @Date: 2022-09-09 16:48:21
   */
  getAllItems(): IAppMenuItem[] {
    const result: IAppMenuItem[] = [];
    const flattenMenus = (menuItems: IAppMenuItem[]): void => {
      menuItems.forEach(item => {
        result.push(item);
        if (item.appMenuItems && item.appMenuItems.length > 0) {
          flattenMenus(item.appMenuItems);
        }
      });
    };
    flattenMenus(this.model.appMenuItems!);
    return result;
  }

  /**
   * 根据id去视图控制器里取得计数器对象
   * @return {*}
   * @author: zhujiamin
   * @Date: 2023-07-10 15:14:21
   */
  getCounter(id: string): AppCounter | null {
    const counters = this.ctx.view.counters;
    if (counters[id]) {
      return counters[id];
    }
    return null;
  }
}
